/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.web.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 排序, 参考 Spring Data Commons
 * <p/>
 *
 * @author vacoor
 */
public class Sort implements Iterable<Sort.Order>, Serializable {
    public static final Direction DEFAULT_DIRECTION = Direction.ASC;

    private final List<Order> orders = new ArrayList<Order>();

    public static Sort create() {
        return new Sort();
    }

    public Sort(Order... orders) {
        for (Order order : orders) {
            add(order);
        }
    }

    public Sort(List<Order> orders) {
        this(orders.toArray(new Order[orders.size()]));
    }

    public Sort(Direction direction, String... properties) {
        for (String p : properties) {
            add(new Order(p, direction));
        }
    }

    public Sort(Sort sort) {
        for (Order order : sort) {
            add(order);
        }
    }

    public Sort asc(String property) {
        return add(Direction.ASC, property);
    }

    public Sort desc(String property) {
        return add(Direction.DESC, property);
    }

    /**
     * 添加一个排序
     */
    public Sort add(Order order) {
        if (order != null) {
            orders.add(order);
        }
        return this;
    }


    public Sort add(Direction dir, String property) {
        return add(new Order(property, dir));
    }

    /**
     * 返回一个新的 将当前排序和给定排序连接后的 Sort
     *
     * @param sort
     * @return
     */
    public Sort and(Sort sort) {
        if (sort == null) {
            return this;
        }

        Sort these = new Sort(this);
        for (Order order : sort) {
            these.add(order);
        }
        return these;
    }

    /**
     * 清空所有排序
     */
    public void clear() {
        orders.clear();
    }

    /**
     * 排序数量
     *
     * @return
     */
    public int size() {
        return orders.size();
    }

    /**
     * 获取给定属性的 排序
     *
     * @param property
     * @return
     */
    public Order getOrderFor(String property) {
        for (Order order : this.orders) {
            if (order.getProperty().equals(property)) {
                return order;
            }
        }
        return null;
    }

    @Override
    public Iterator<Order> iterator() {
        return orders.iterator();
    }

    @Override
    public String toString() {
        return "Sort{" + "orders=" + orders + '}';
    }

    // ----------------------

    /**
     * 排序方式
     */
    public enum Direction {
        ASC, DESC;

        /**
         * 不能转换返回 null
         *
         * @param name
         * @return
         */
        public static Direction forName(String name) {
            try {
                return valueOf(name.toUpperCase());
            } catch (Exception e) {
                return null;
            }
        }
    }

    /**
     * 排序
     */
    public static class Order {
        private String property;
        private Direction direction;

        public Order() {
            this(null, DEFAULT_DIRECTION);
        }

        public Order(final String property, final Direction direction) {
            this.property = property;
            this.direction = direction == null ? DEFAULT_DIRECTION : direction;
        }

        public String getProperty() {
            return property;
        }

        public void setProperty(String property) {
            this.property = property;
        }

        public Direction getDirection() {
            return direction;
        }

        public void setDirection(Direction direction) {
            this.direction = direction;
        }

        /**
         * 为给定属性创建递增(ascending)排序
         */
        public static Order asc(String property) {
            return new Order(property, Direction.ASC);
        }

        /**
         * 为给定属性创建递减(descending)排序
         */
        public static Order desc(String property) {
            return new Order(property, Direction.DESC);
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Order order = (Order) o;

            if (direction != order.direction) return false;
            if (property != null ? !property.equals(order.property) : order.property != null) return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = property != null ? property.hashCode() : 0;
            result = 31 * result + (direction != null ? direction.hashCode() : 0);
            return result;
        }

        @Override
        public String toString() {
            return "Order{" +
                    "property='" + property + '\'' +
                    ", direction=" + direction +
                    '}';
        }
    }
}
